﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Xml.Serialization;
using System.Globalization;
using System.Threading;
using DatabaseLib;
using System.Timers;
using Microsoft.DirectX.AudioVideoPlayback;
using System.Diagnostics;

namespace ELDownloader
{
    public partial class frmMain : Form
    {

        Queue<DateTime> AGWDateQueue;
        Guid AGWID;
        private string[] AllowFileTypes = new string[] { ".jpg", ".gif", ".png", ".mpg", ".mpeg", ".avi", ".wmv" };
        DB db;
        Guid ELID;
        Queue<string> ELSitesQueue;
        private string[] ImageTypes = new string[] { ".jpg", ".gif", ".png" };
        int OrigQueueSize;
        Queue<stSaveFileQueueItem> SaveFileQueue;
        public cSettings Settings;
        bool[] ThreadComplete;
        System.Timers.Timer UpdateTimer;
        System.Timers.Timer AutoDownloadRemainTimer;
        TimeSpan AutoDownloadRemaining;
        Video video;
        System.Timers.Timer VideoTimer;
        private string[] VideoTypes = new string[] { ".mpg", ".mpeg", ".avi", ".wmv" };
        bool Working;
        StreamWriter Log;
        DateTime LogDate;
        Thread DTToTVThread;



        private enum eSearchLineDirection {Horizontal, Vertical};
        private enum eProcessState { Stopped, Working, Complete };



        public frmMain()
        {
            InitializeComponent();
            Settings = new cSettings();
            LoadSettings();
        }


        private void WriteToLog(string aMessage)
        {
            if (!DateTime.Now.Date.Equals(LogDate.Date))
                InitializeLog();
            Log.Write("[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") + "] " + aMessage + "\r\n");            
            
            //Log.Flush();
        }


        private delegate void dChangeButtonsEnabled();
        delegate bool dCheckColor();
        delegate double dFunc (double coord);
        private delegate void dSetThreadPBEnable(int ThreadNum, bool Enabled);
        private delegate void dTV_AfterSelect(object sender, TreeViewEventArgs e);
        private delegate void dUpdateProcessState(eProcessState ProcessState);
        private delegate void dUpdateStat();
        private delegate void dUpdateThreadStatus(int ThreadNum, int Percentage);
        private delegate void dUpdateTotalLabel(int Count);
        private delegate void dUpdateTotalProgress(int Percentage);
        private delegate void dUpdateTV(bool ShowNewOnly);





        public string DownloadWebPage(Uri Link)
        {
            WriteToLog("Trying to download webpage: "+Link.ToString());
            string Result = string.Empty;
            WebClient wc = new WebClient();
            try
            {
                Result = wc.DownloadString(Link);
            }
            catch
            {
                Result = string.Empty;
            }
            return Result;
        }


        private void AutoDownload(Object sender, ElapsedEventArgs e)
        {
            WriteToLog("Start autodownload");
            WriteToLog("Get new links for EL");
            while (Working)
                Thread.Sleep(500);
            ParseEL();
            while (Working)
                Thread.Sleep(500);
            WriteToLog("Get new links for AGW");
            SearchAGWLinks(DateTime.Now, DateTime.Now);
            while (Working)
                Thread.Sleep(500);
            WriteToLog("Download data");
            DownloadAll(null, null);
        }

        private void bSett_Click(object sender, EventArgs e)
        {
            frmSett Sett = new frmSett();
            Sett.tbRootpath.Text = Settings.RootPath;
            Sett.tbSDFFilename.Text = Settings.SDFFilename;
            Sett.nudAuto.Value = Settings.AutoDownloadPeriod/3600000;
            Sett.nudThreads.Value = Settings.ThreadsCount;
            if (Sett.ShowDialog() == DialogResult.OK)
            {
                Settings.RootPath = Sett.tbRootpath.Text;
                Settings.SDFFilename = Sett.tbSDFFilename.Text;
                Settings.AutoDownloadPeriod = (int)Sett.nudAuto.Value*3600000;
                Settings.ThreadsCount = (int)Sett.nudThreads.Value;
                SaveSettings();
                MessageBox.Show("To apply changes restart program");
            }
        }

        private void bStop_Click(object sender, EventArgs e)
        {
            Working = false;
        }

        private void ChangeButtonsEnabled()
        {
            if (cbShowNewOnly.InvokeRequired)
            {
                dChangeButtonsEnabled d = new dChangeButtonsEnabled(ChangeButtonsEnabled);
                this.Invoke(d);
            }
            else
            {
                cbShowNewOnly.Enabled = !Working;
                downloadNewLinksToolStripMenuItem.Enabled = !Working;
                tsmiDownloadAll.Enabled = !Working;
                tsmiDownloadSite.Enabled = !Working;
                tsmiDelete.Enabled = !Working;
                bStop.Enabled = Working;
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            UpdateTV(cbShowNewOnly.Checked);
        }

        private void cbAutoDownload_CheckedChanged(object sender, EventArgs e)
        {
            UpdateTimer.Enabled = cbAutoDownload.Checked;
            if (cbAutoDownload.Checked)
                AutoDownloadRemaining = new TimeSpan(0, 0, 0, 0, Settings.AutoDownloadPeriod);
            else
                cbAutoDownload.Text = "Autodownload (00:00:00)";

            AutoDownloadRemainTimer.Enabled = cbAutoDownload.Checked;
        }

        private bool CheckForComplete()
        {
            bool Result = true;
            for (int i = 0; i < Settings.ThreadsCount; i++)
            {
                Result = Result & ThreadComplete[i];
                SetThreadPBEnable(i, !ThreadComplete[i]);
            }
            return Result;
        }

        private int CutImage(string FileName)
        {
            Bitmap Img = new Bitmap(FileName);
            return CutImage(Img, FileName);
        }

        private int CutImage(Bitmap Img, string OrigFileName)
        {
            WriteToLog("Try to cut image: "+OrigFileName);
            int Saved = 1;
            Bitmap CuttedImage;
            PointF Point1 = new PointF();
            PointF Point2 = new PointF();
            eSearchLineDirection SearchDirection = eSearchLineDirection.Vertical;
            int i;
            while (FindWhiteLine(Img, ref Point1, ref Point2, ref SearchDirection))
            {
                WriteToLog("Founded white line at P1: " + Point1.X.ToString() + "," + Point1.Y.ToString() + "; P2: " + Point2.X.ToString() + "," + Point2.Y.ToString()+"; Direction: "+SearchDirection.ToString());
                CuttedImage = Img.Clone(new RectangleF(0, 0, Point2.X, Point2.Y), System.Drawing.Imaging.PixelFormat.Undefined);
                Saved += CutImage(CuttedImage, OrigFileName);
                if (SearchDirection == eSearchLineDirection.Vertical)
                    Img = Img.Clone(new RectangleF(Point1.X, Point1.Y + 1, Point2.X, Img.Height - Point1.Y - 1), System.Drawing.Imaging.PixelFormat.Undefined);
                else
                    Img = Img.Clone(new RectangleF(Point1.X + 1, Point1.Y, Img.Width - Point1.X - 1, Point2.Y), System.Drawing.Imaging.PixelFormat.Undefined);
            }
            i = 0;
            string ImgFileName;
            while (File.Exists(ImgFileName = Path.Combine(Path.GetDirectoryName(OrigFileName), Path.GetFileNameWithoutExtension(OrigFileName) + "_" + i.ToString() + Path.GetExtension(OrigFileName))))
            {
                i++;
            }
            ImageCodecInfo ici = GetEncoderInfo(GetMimeType(Path.GetExtension(ImgFileName)));
            EncoderParameters eps = new EncoderParameters(1);
            eps.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 85L);
            WriteToLog("Save image: "+ImgFileName);
            Img.Save(ImgFileName,ici, eps);
            return Saved;
        }

//        private void cutToolStripMenuItem_Click(object sender, EventArgs e)
//        {
//            if (lvLinks.SelectedItems.Count != 0)
//                if (lvLinks.SelectedItems[0].SubItems[1].Text != "0")
//                {
//                    Guid LinkID = (Guid)lvLinks.SelectedItems[0].Tag;
//                    string FilePath = Path.Combine(Settings.RootPath,
//                    db.GetQueryValue(@"Select (TRS.Name+'\'+TG.Name+'\'+TSG.Name+'\'+CONVERT(nvarchar(8),TS.DTStamp, 112)+'\'+CONVERT(nvarchar(36),TS.SiteID)+'\') Path from 
//                    TSublinks TSL inner join 
//                    TSites TS on TSL.SiteID = TS.SiteID inner join
//                    TGenres TG on TS.GenreID = TG.GenreID inner join
//                    TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID inner join
//                    TLinks TL on TSL.LinkID = TL.LinkID inner join
//                    TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
//                    WHERE TL.LinkID = '" + LinkID.ToString() + "'"));
//                    string FileName = Path.GetFileName(lvLinks.SelectedItems[0].Text);
//                    string FullFileName = Path.Combine(Path.Combine(Settings.RootPath, FilePath), FileName);                    
//                    CutImage(FullFileName);
//                }

//        }

        private void Download(object sender, EventArgs e)
        {
            
            Guid RootSiteID = Guid.Empty;
            string GenreID = string.Empty;
            string SubGenreID = string.Empty;
            string DTStamp = string.Empty;
            string SiteID = string.Empty;
            if (TV.SelectedNode == null)
            {
                MessageBox.Show("Node are not selected");
                return;
            }
            WriteToLog("Start download elements: " + TV.SelectedNode.FullPath);
            TreeNode TVNode = TV.SelectedNode;
            while (TVNode != null)
            {
                switch (TVNode.Level)
                {
                    case 0:
                        {
                            RootSiteID = new Guid(TVNode.Name);
                            break;
                        }
                    case 1:
                        {
                            GenreID = TVNode.Name;
                            break;
                        }
                    case 2:
                        {
                            SubGenreID = TVNode.Name;
                            break;
                        }
                    case 3:
                        {
                            DTStamp = TVNode.Name;
                            break;
                        }
                    case 4:
                        {
                            SiteID = TVNode.Name;
                            break;
                        }
                }
                TVNode = TVNode.Parent;
            }
            string Where = " where ";
            switch (TV.SelectedNode.Level)
            {
                case 0:
                    {
                        Where += "TS.RootsiteID = '" + RootSiteID.ToString() + "'";
                        break;
                    }
                case 1:
                    {
                        foreach (ToolStripMenuItem tsmi in genresToolStripMenuItem.DropDownItems)
                        {
                            if ((tsmi.Tag.ToString() == GenreID) && (!tsmi.Checked))
                            {
                                MessageBox.Show("You cannot download this genre until it unchecked to download");
                                return;
                            }
                        }
                        Where += "TS.GenreID = '" + GenreID + "'";
                        break;
                    }
                case 2:
                    {
                        Where += "TS.SubGenreID = '" + SubGenreID + "'";
                        break;
                    }
                case 3:
                    {
                        Where += "TS.DTStamp = '" + DTStamp + "'";
                        break;
                    }
                case 4:
                    {
                        Where += "TS.SiteID = '" + SiteID + "'";
                        break;
                    }
            }
            string GenreWhere = string.Empty;
            if (TV.SelectedNode.Level != 3)
            {
                
                foreach (ToolStripMenuItem tsmi in genresToolStripMenuItem.DropDownItems)
                {
                    if (tsmi.Checked)
                    {
                        if (GenreWhere != string.Empty)
                            GenreWhere += " OR ";
                        GenreWhere += " TS.GenreID = '" + tsmi.Tag.ToString() + "' ";
                    }
                }
                if (GenreWhere != string.Empty)
                    GenreWhere = " AND (" + GenreWhere + ")";
            }
            if (RootSiteID == ELID)
            {
                if (!alwaysDownloadAgainToolStripMenuItem.Checked)
                    Where += " AND TSL.Filesize = 0";
                if (!downloadFileWithTryings10ToolStripMenuItem.Checked)
                    Where += "AND TSL.DLTryings < 10";
            }
            else
                Where += " AND TSL.SublinkID IS NULL";

            DataTable DT;
            if (RootSiteID == ELID)
                DT = db.GetQueryTable(@"Select TSL.SublinkID from TSublinks TSL inner join
                TSites TS on TS.SiteID = TSL.SiteID" + Where+GenreWhere);
            else
                DT = db.GetQueryTable(@"Select TS.SiteID from TSites TS left join TSubLinks TSL on TSL.SiteID = TS.SiteID" + Where+GenreWhere);
            if (DT.Rows.Count > 0)
            {
                SaveFileQueue.Clear();
                foreach (DataRow DR in DT.Rows)
                {
                    stSaveFileQueueItem SaveFileQueueItem = new stSaveFileQueueItem();
                    SaveFileQueueItem.RootSiteID = RootSiteID;
                    SaveFileQueueItem.ItemID = (Guid)DR[0];
                    SaveFileQueue.Enqueue(SaveFileQueueItem);
                }
                OrigQueueSize = SaveFileQueue.Count;
            }
            TotalPB.Value = 0;
            if (OrigQueueSize > 0)
                SaveFiles();
        }

        private void DownloadAll(object sender, EventArgs e)
        {
            WriteToLog("Start download all elements");
            string Where = " where TS.RootSiteID = '"+ELID+"'";
            if (!alwaysDownloadAgainToolStripMenuItem.Checked)
                Where += " AND TSL.Filesize = 0";
            if (!downloadFileWithTryings10ToolStripMenuItem.Checked)
                Where += " AND TSL.DLTryings < 10";

            string GenreWhere = string.Empty;
            foreach (ToolStripMenuItem tsmi in genresToolStripMenuItem.DropDownItems)
            {
                if (tsmi.Checked)
                {
                    if (GenreWhere != string.Empty)
                        GenreWhere += " OR ";
                    GenreWhere += "TS.GenreID = '" + tsmi.Tag.ToString() + "' ";
                }
            }
            if (GenreWhere != string.Empty)
                GenreWhere = " AND (" + GenreWhere + ")";

            SaveFileQueue.Clear();
            DataTable DT = db.GetQueryTable(@"select TSL.SublinkID from TSublinks TSL 
                    inner  join TSites TS on TSL.SiteID = TS.SiteID "+Where+GenreWhere);
            if (DT.Rows.Count > 0)
            {
                foreach (DataRow DR in DT.Rows)
                {
                    stSaveFileQueueItem SaveFileQueueItem = new stSaveFileQueueItem();
                    SaveFileQueueItem.ItemID = (Guid)DR[0];
                    SaveFileQueueItem.RootSiteID = ELID;
                    SaveFileQueue.Enqueue(SaveFileQueueItem);
                }
            }
            DT = db.GetQueryTable(@"select TS.SiteID from TSites TS left join TSubLinks TSL on TSL.SiteID = TS.SiteID
                    Where TS.RootSiteID = '"+AGWID+"' AND TSL.SubLInkID IS NULL"+GenreWhere);
            if (DT.Rows.Count > 0)
            {
                foreach (DataRow DR in DT.Rows)
                {
                    stSaveFileQueueItem SaveFileQueueItem = new stSaveFileQueueItem();
                    SaveFileQueueItem.ItemID = (Guid)DR[0];
                    SaveFileQueueItem.RootSiteID = AGWID;
                    SaveFileQueue.Enqueue(SaveFileQueueItem);
                }
            }
            OrigQueueSize = SaveFileQueue.Count;
            TotalPB.Value = 0;
            if (OrigQueueSize > 0)
                SaveFiles();
        }

        private void DownloadNewLinksAGW(object sender, EventArgs e)
        {
            frmSelectPeriod SelectPeriod = new frmSelectPeriod();
            if (SelectPeriod.ShowDialog() == DialogResult.OK)
            {
                SearchAGWLinks(SelectPeriod.dtpFromDate.Value, SelectPeriod.dtpToDate.Value);
            }
        }

        private void SearchAGWLinks(DateTime StartDate, DateTime EndDate)
        {
            Working = true;
            ChangeButtonsEnabled();
            WriteToLog("Search agw links for period: " + StartDate.ToString("dd.MM.yyyy") + " - " + EndDate.ToString("dd.MM.yyyy"));
            DateTime DT = StartDate;
            while (DT <= EndDate)
            {
                AGWDateQueue.Enqueue(DT);
                DT = DT.AddDays(1);
            }
            OrigQueueSize = AGWDateQueue.Count;
            ResetThreadPB();
            UpdateProcessState(eProcessState.Working);
            for (int i = 0; i < Settings.ThreadsCount; i++)
            {
                ThreadComplete[i] = false;
                Thread DLThread = new Thread(GetAGWLinks);
                DLThread.Start(i);
            }
        }

        private void DownloadNewLinksEL(object sender, EventArgs e)
        {
            ParseEL();
            //UpdateTV(cbShowNewOnly.Checked);
        }

        private void DTToTV(DataTable DT, TreeNode ELNode, TreeNode AGWNode)
        {
            WriteToLog("Fill TreeView from DataTable");
            TreeNode RootItem;
            TreeNode SubGenreItem;
            TreeNode DateItem;
            TreeNode SiteItem;
            string Genre;
            string GID;
            string SubGenre;
            string SGID;
            string DateStamp;
            string DTStamp;
            string SiteID;
            int SearchResult;
            
            if (DT.Rows.Count > 0)
                foreach (DataRow DR in DT.Rows)
                {
                    Genre = DR["Genre"].ToString();
                    GID = DR["GID"].ToString();
                    SubGenre = DR["SubGenre"].ToString();
                    SGID = DR["SGID"].ToString();
                    DateStamp = ((DateTime)DR["DateStamp"]).ToString("dd.MM.yyyy", CultureInfo.InvariantCulture);
                    DTStamp = ((DateTime)DR["DateStamp"]).ToString("yyyyMMdd", CultureInfo.InvariantCulture);
                    SiteID = DR["SiteID"].ToString();
                    TreeNode RootSiteNode = new TreeNode();
                    if (ELID.Equals((Guid)DR["RootSiteID"]))
                        RootSiteNode = ELNode;
                    else
                        if (AGWID.Equals((Guid)DR["RootSiteID"]))
                            RootSiteNode = AGWNode;


                    SearchResult = RootSiteNode.Nodes.IndexOfKey(GID);
                    if (SearchResult != -1)
                    {
                        RootItem = RootSiteNode.Nodes[SearchResult];
                    }
                    else
                    {
                        RootItem = RootSiteNode.Nodes.Add(GID, Genre);
                        RootItem.ImageIndex = 2;
                        RootItem.SelectedImageIndex = 2;
                    }

                    SearchResult = RootItem.Nodes.IndexOfKey(SGID);
                    if (SearchResult != -1)
                    {
                        SubGenreItem = RootItem.Nodes[SearchResult];
                    }
                    else
                    {
                        SubGenreItem = RootItem.Nodes.Add(SGID, SubGenre);
                        SubGenreItem.ImageIndex = 3;
                        SubGenreItem.SelectedImageIndex = 3;
                    }

                    SearchResult = SubGenreItem.Nodes.IndexOfKey(DTStamp);
                    if (SearchResult != -1)
                    {
                        DateItem = SubGenreItem.Nodes[SearchResult];
                    }
                    else
                    {
                        DateItem = SubGenreItem.Nodes.Add(DTStamp, DateStamp);
                        DateItem.ImageIndex = 4;
                        DateItem.SelectedImageIndex = 4;
                    }


                    SiteItem = DateItem.Nodes.Add(SiteID, DR["Link"].ToString());
                    SiteItem.ImageIndex = 5;
                    SiteItem.SelectedImageIndex = 5;

                }
        }

        private stATag ExtractATag(string atag)
        {
            stATag Result = new stATag();
            try
            {
                int startlink = atag.IndexOf("href=", StringComparison.CurrentCultureIgnoreCase) + 5;
                int endlink1 = atag.IndexOf(" ", startlink, StringComparison.CurrentCultureIgnoreCase);
                int endlink2 = atag.IndexOf(">", startlink, StringComparison.CurrentCultureIgnoreCase);
                int endlink;
                if ((endlink1 != -1) && (endlink1 < endlink2))
                    endlink = endlink1;
                else
                    endlink = endlink2;

                if (endlink == -1)
                    endlink = atag.Length - 1;

                Result.Link = atag.Substring(startlink, endlink - startlink).Replace("\n", "").Replace("\"", "").Trim();
                int closetagindex = atag.IndexOf("</a>", StringComparison.CurrentCultureIgnoreCase);
                int opentagend = atag.IndexOf(">");                
                if (closetagindex == -1)
                    Result.Text = atag.Substring(opentagend + 1, atag.Length - opentagend - 1);
                else
                    Result.Text = atag.Substring(opentagend + 1, closetagindex - opentagend - 1);
            }
            catch
            {
            }
            return Result;
        }

        private bool FindWhiteLine(Bitmap bmp, ref PointF Point1, ref PointF Point2, ref eSearchLineDirection SearchDirection)
        {
            double WhitePrecision = 0.3F; //30 percent
            float MinX=100;
            float MinY=100;            
            bool Result = false;
            SearchDirection = eSearchLineDirection.Vertical;
            if ((bmp.Width < MinX) || (bmp.Height < MinY))
                return false;
            for (float y = MinY; y < bmp.Height; y++)
            {
                Point1.X = 0;
                Point1.Y = y;
                Point2.X = (float)bmp.Width-1;                
                Point2.Y = y;
                Result = IsLineColor(bmp, Point1, Point2, Color.White, WhitePrecision);
                if (Result)
                    break;
            }
            if (!Result)
            {
                SearchDirection = eSearchLineDirection.Horizontal;
                for (float x = MinX; x < bmp.Width; x++)
                {
                    Point1.X = x;
                    Point1.Y = 0;
                    Point2.X = x;
                    Point2.Y = (float)bmp.Height - 1;
                    Result = IsLineColor(bmp, Point1, Point2, Color.White, WhitePrecision);
                    if (Result)
                        break;
                }
            }
            return Result;
        }

        private void InitializeLog()
        {
            if (Log != null)
                Log.Close();
            LogDate = DateTime.Now;
            Log = new StreamWriter(Path.Combine(Application.StartupPath, "log" + LogDate.ToString("yyyyMMdd") + ".txt"), true);
            Log.AutoFlush = true;
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            if ((Settings.SDFFilename == string.Empty) || (Settings.RootPath == string.Empty))
            {
                bSett_Click(null, null);
            }

            if ((Settings.SDFFilename == string.Empty) || (Settings.RootPath == string.Empty))
                Application.Exit();
            else
            {
                InitializeLog();
                WriteToLog("Application started");
                //DBFileName = @"c:\Users\George\Documents\Visual Studio 2010\Projects\ELDownloader\ELDownloader\Main.sdf";
                ConnectionConfig conn = new ConnectionConfig(DatabaseTypes.typeMsSqlCE);
                conn.SDFFilename = Settings.SDFFilename;
                db = new DB(conn);
                ELID = db.GetOrInsertID("TRootSites", new string[] { "RootSiteID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, "Elephant List" }, new int[] { 1 });
                AGWID = db.GetOrInsertID("TRootSites", new string[] { "RootSiteID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, "Amateurs Gone Wild" }, new int[] { 1 });
                //RootPath = Application.StartupPath;
                UpdateTV(cbShowNewOnly.Checked);
                UpdateGenresMenuItems();
                lvwColumnSorter = new ListViewColumnSorter();
                lvLinks.ListViewItemSorter = lvwColumnSorter;
                SaveFileQueue = new Queue<stSaveFileQueueItem>();
                ELSitesQueue = new Queue<string>();
                AGWDateQueue = new Queue<DateTime>();
                for (int i = 0; i < Settings.ThreadsCount; i++)
                {
                    ToolStripStatusLabel tsslThread = new ToolStripStatusLabel(i.ToString());
                    ToolStripProgressBar tspbThread = new ToolStripProgressBar("Thread " + i.ToString());
                    tspbThread.ProgressBar.Width = 20;
                    tspbThread.Style = ProgressBarStyle.Continuous;
                    statusStrip1.Items.Insert(1 + i * 2, tsslThread);
                    statusStrip1.Items.Insert(1 + (i * 2 + 1), tspbThread);
                }
                ThreadComplete = new bool[Settings.ThreadsCount];
                AutoDownloadRemainTimer = new System.Timers.Timer(1000);
                AutoDownloadRemainTimer.Elapsed += new ElapsedEventHandler(AutoDownloadRemainTimer_Elapsed);
                UpdateTimer = new System.Timers.Timer();
                UpdateTimer.Interval = Settings.AutoDownloadPeriod;
                UpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(AutoDownload);
                UpdateStat();
            }
        }

        private void UpdateGenresMenuItems()
        {
            genresToolStripMenuItem.DropDownItems.Clear();
            DataTable DTGenres = db.GetQueryTable("Select GenreID, Name from TGenres order by Name");
            if (DTGenres.Rows.Count > 0)
            {
                foreach (DataRow DR in DTGenres.Rows)
                {
                    ToolStripMenuItem tsmiGenre = new ToolStripMenuItem();
                    tsmiGenre.Tag = DR[0];
                    tsmiGenre.Text = DR[1].ToString();
                    tsmiGenre.CheckOnClick = true;
                    tsmiGenre.Checked = true;
                    genresToolStripMenuItem.DropDownItems.Add(tsmiGenre);
                }
            }
        }

        private delegate void dAutoDownloadRemainTimer_Elapsed(object sender, EventArgs e);
        private void AutoDownloadRemainTimer_Elapsed(object sender, EventArgs e)
        {
            if (cbAutoDownload.InvokeRequired)
            {
                dAutoDownloadRemainTimer_Elapsed d = new dAutoDownloadRemainTimer_Elapsed(AutoDownloadRemainTimer_Elapsed);
                this.Invoke(d, new object[] { sender, e });
            }
            else
            {
                AutoDownloadRemaining = AutoDownloadRemaining.Subtract(new TimeSpan(0,0,0,1));
                if (AutoDownloadRemaining.TotalMilliseconds < 0)
                    AutoDownloadRemaining = AutoDownloadRemaining.Add(new TimeSpan(0,0,0,0,Settings.AutoDownloadPeriod));
                    cbAutoDownload.Text = "Autodownload (" + AutoDownloadRemaining.ToString("c") + ")";
            }
        }

        private void GetAGWLinks(object ThreadNum)
        {
            while ((AGWDateQueue.Count > 0) && (Working))
            {
                DateTime DT;
                lock (AGWDateQueue)
                {
                    try
                    {
                        DT = AGWDateQueue.Dequeue();
                    }
                    catch
                    {
                        break;
                    }
                }
                int TotalPercentage = (int)(((double)(OrigQueueSize - AGWDateQueue.Count) / (double)OrigQueueSize) * 100);
                UpdateTotalProgress(TotalPercentage);
                UpdateTotalLabel(AGWDateQueue.Count);
                string PreLink = "http://static.amateurs-gone-wild.com/content/files4/";
                string Genre = "Pictures";
                Guid gGenre = Guid.Empty;
                lock (db)
                {
                    gGenre = db.GetOrInsertID("TGenres", new string[] { "GenreID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, Genre }, new int[] { 1 });
                }
                string SubGenre = "Amateurs";
                Guid gSubGenre = db.GetOrInsertID("TSubGenres", new string[] { "SubGenreID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, SubGenre }, new int[] { 1 });
                List<string> QueryList = new List<string>();
                for (int i = 1; i < 10; i++)
                {
                    UpdateThreadStatus((int)ThreadNum, (int)(((double)i / 9) * 100));
                    string SiteLink = PreLink + DT.ToString("yyMMdd") + i.ToString("D2") + ".jpg";
                    if (DBNull.Value.Equals(db.GetQueryObject("select LinkID from TLinks where Link = '" + SiteLink + "'")))
                    {
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(SiteLink);
                        try
                        {
                            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                            response.Close();
                            if (response.StatusCode == HttpStatusCode.OK)
                            {
                                Guid gLink = db.GetOrInsertID("TLinks", new string[] { "LinkID", "Link" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, SiteLink }, new int[] { 1 });
                                string Query = @"insert into TSites (SiteID, RootSiteID, GenreID, SubGenreID, LinkID, DTStamp)
                                        values (NEWID(), '" + AGWID.ToString() + "', '" + gGenre.ToString() + "','"+gSubGenre.ToString()+"','"+gLink.ToString()+"','"+DT.ToString("yyyyMMdd")+"')";
                                QueryList.Add(Query);
                            }
                        }
                        catch (WebException ex)
                        {
                        }
                    }
                }
                db.ExecuteQueryBatch(QueryList);
                
            }
            ThreadComplete[(int)ThreadNum] = true;
            if (CheckForComplete())
            {
                Working = false;
                ChangeButtonsEnabled();
                UpdateStat();
                UpdateProcessState(eProcessState.Complete);
                UpdateTV(cbShowNewOnly.Checked);
                //MessageBox.Show("Готово");
            }
        }

        private static ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            j = 0x007;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        private string GetMimeType(string fileName)
        {
            string mimeType = "application/unknown";
            string ext = System.IO.Path.GetExtension(fileName).ToLower();
            Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(ext);
            if (regKey != null && regKey.GetValue("Content Type") != null)
                mimeType = regKey.GetValue("Content Type").ToString();
            return mimeType;
        }

        private List<string> GetSubLinks(int ThreadNum, string SiteLink, Guid SiteID)
        {
            //string sSiteLink = db.GetQueryValue("select TL.Link from TSites TS left join TLinks TL on TS.LinkID = TL.LinkID where TS.SiteID = '" + Site.ToString() + "'");
            Uri SiteHost = new Uri(SiteLink.Substring(0, SiteLink.LastIndexOf('/') + 1));
            string Page = DownloadWebPage(new Uri(SiteLink));
            List<string> SubLinks = new List<string>();
            int OrigPageLength = Page.Length;
            if (Page.Length > 0)
            {
                while (Page.IndexOf("<a", StringComparison.CurrentCultureIgnoreCase) != -1)
                {
                    UpdateThreadStatus(ThreadNum, (int)(((double)(OrigPageLength - Page.Length) / (double)OrigPageLength) * 100));
                    int startahref = Page.IndexOf("<a", StringComparison.CurrentCultureIgnoreCase);
                    int endahref = Page.IndexOf("</a>", startahref, StringComparison.CurrentCultureIgnoreCase);
                    if (endahref == -1)
                        endahref = Page.Length - 1;
                    else
                        endahref += 4;
                    stATag ATag = ExtractATag(Page.Substring(startahref, endahref - startahref));
                    if (ATag.Text.IndexOf("<img ", StringComparison.CurrentCultureIgnoreCase) != -1)
                    {
                        try
                        {
                            if (Array.Exists(AllowFileTypes, delegate(string obj) { return obj == Path.GetExtension(ATag.Link).ToLower(); }))
                            {
                                if (!Uri.IsWellFormedUriString(ATag.Link, UriKind.Absolute))
                                    ATag.Link = new Uri(SiteHost, ATag.Link).ToString();
                                if (Uri.IsWellFormedUriString(ATag.Link, UriKind.Absolute))
                                {
                                    Guid LinkID = db.GetOrInsertID("Tlinks", new string[] { "LinkID", "Link" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, ATag.Link }, new int[] { 1 });
                                    string Query = @"INSERT INTO [TSubLinks]
		                                    ([SubLinkID]
		                                    ,[SiteID]
		                                    ,[LinkID]
		                                    ,[FileSize]
                                            ,[DLTryings])
	                                        VALUES
		                                    (NEWID()
		                                    ,'" + SiteID.ToString() + @"'
		                                    ,'" + LinkID.ToString() + @"'
		                                    ,0
                                            ,0)";
                                    SubLinks.Add(Query);
                                }
                            }
                        }
                        catch
                        {
                        }
                    }
                    Page = Page.Substring(endahref);
                }
            }
            return SubLinks;

        }

        private bool IsLineColor(Bitmap bmp, PointF Point1, PointF Point2, Color NeedColor, double ColorPrecision)
        {
            bool Result = true;
            double y = Point1.Y;
            double x = Point1.X;

            dFunc CalcY = (double px) => { return (-px * (Point1.Y - Point2.Y) - Point1.X * Point2.Y + Point2.X * Point1.Y) / (Point2.X - Point1.X); };
            dFunc CalcX = (double py) => { return (-py * (Point2.X - Point1.X) - Point1.X * Point2.Y + Point2.X * Point1.Y) / (Point1.Y - Point2.Y); };
            dFunc Func;
            bool LineIsVertical = Point1.X == Point2.X;
            Func = (LineIsVertical) ? CalcX : CalcY;

            int MinR = (int)(NeedColor.R - (NeedColor.R * ColorPrecision));
            int MaxR = (int)(NeedColor.R + (NeedColor.R * ColorPrecision));
            if (MaxR > 255) MaxR = 255;
            int MinG = (int)(NeedColor.G - (NeedColor.G * ColorPrecision));
            int MaxG = (int)(NeedColor.G + (NeedColor.G * ColorPrecision));
            if (MaxG > 255) MaxG = 255;
            int MinB = (int)(NeedColor.B - (NeedColor.B * ColorPrecision));
            int MaxB = (int)(NeedColor.B + (NeedColor.B * ColorPrecision));
            if (MaxB > 255) MaxB = 255;
            dCheckColor CheckColor = () => { 
                Color PixColor = bmp.GetPixel((int)x, (int)y);
                return Result & ((PixColor.R > MinR) && (PixColor.R <= MaxR) && (PixColor.G > MinG) && (PixColor.G <= MaxG) && (PixColor.B > MinB) && (PixColor.B <= MaxB)); };

            if (!LineIsVertical)
            {
                if (Point1.X < Point2.X)
                    while (x <= Point2.X)
                    {
                        y = Func(x);
                        if (double.IsNaN(y))
                            y = 0;
                        Result = CheckColor();
                        if (!Result)
                            break;
                        x++;
                    }
                else
                    while (x >= Point2.X)
                    {
                        y = Func(x);
                        if (double.IsNaN(y))
                            y = 0;
                        Result = CheckColor();
                        if (!Result)
                            break;
                        x--;
                    }
            }
            else
            {
                if (Point1.Y < Point2.Y)
                    while (y <= Point2.Y)
                    {
                        x = Func(y);
                        if (double.IsNaN(x))
                            x = 0;
                        Result = CheckColor();
                        if (!Result)
                            break;
                        y++;
                    }
                else
                    while (y >= Point2.Y)
                    {
                        x = Func(y);
                        if (double.IsNaN(x))
                            x = 0;
                        Result = CheckColor();
                        if (!Result)
                            break;
                        y--;
                    }
            }

            return Result;
        }

        private void LoadSettings()
        {
            if (File.Exists(Path.Combine(Application.StartupPath,"settings.xml")))
            {
                XmlSerializer reader = new XmlSerializer(Settings.GetType());
                StreamReader file = new StreamReader(Path.Combine(Application.StartupPath,"settings.xml"), Encoding.UTF8);
                Settings = (cSettings)reader.Deserialize(file);
                file.Close();
            }

        }

        private void lvLinks_SelectedIndexChanged(object sender, EventArgs e)
        {            
            if (lvLinks.SelectedItems.Count != 0)
                if (lvLinks.SelectedItems[0].SubItems[1].Text != "0")
                {
                    Guid LinkID = (Guid)lvLinks.SelectedItems[0].Tag;
                    string FilePath = Path.Combine(Settings.RootPath,
                    db.GetQueryValue(@"Select (TRS.Name+'\'+TG.Name+'\'+TSG.Name+'\'+CONVERT(nvarchar(8),TS.DTStamp, 112)+'\'+CONVERT(nvarchar(36),TS.SiteID)+'\') Path from 
                    TSublinks TSL inner join 
                    TSites TS on TSL.SiteID = TS.SiteID inner join
                    TGenres TG on TS.GenreID = TG.GenreID inner join
                    TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID inner join
                    TLinks TL on TSL.LinkID = TL.LinkID inner join
                    TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                    WHERE TL.LinkID = '" + LinkID.ToString() + "'"));
                    string FileName = Path.GetFileName(lvLinks.SelectedItems[0].Text);
                    string FullFileName = Path.Combine(FilePath,FileName);
                    pbPreview.Tag = FullFileName;
                    if ((video != null) && (video.Playing))
                        video.Stop();
                    if (video != null)
                        video.Dispose();
                    video = null;
                    if (VideoTimer != null)
                        VideoTimer.Dispose();
                    VideoTimer = null;
                    try
                    {
                        if (Array.Exists(ImageTypes, delegate(string obj) { return obj == Path.GetExtension(FullFileName).ToLower(); }))
                        {
                            playToolStripMenuItem.Visible = false;
                            stopToolStripMenuItem.Visible = false;
                            pbPreviewProgress.Visible = false;
                            pbPreview.Dock = DockStyle.Fill;
                            pbPreview.Load(new Uri(FullFileName).AbsoluteUri);
                        }
                        else
                        {
                            playToolStripMenuItem.Visible = true;
                            stopToolStripMenuItem.Visible = true;
                            pbPreviewProgress.Visible = true;
                            pbPreview.Dock = DockStyle.None;
                            VideoTimer = new System.Timers.Timer(100);
                            VideoTimer.Elapsed += VideoTimer_Elapsed;
                            video = new Video(FullFileName);
                            video.Owner = pbPreview;
                            splitContainer2_Panel2_Resize(null, null);
                            video.Ending += VideoEnding;
                            pbPreviewProgress.Maximum = (int)video.Duration;
                            VideoTimer.Start();
                            video.Play();
                            stopToolStripMenuItem.Enabled = true;
                            playToolStripMenuItem.Enabled = false;

                        }
                    }
                    catch
                    {
                    }
                }
        }

        private delegate void dVideoTimer_Elapsed(object sender, EventArgs e);

        private void VideoTimer_Elapsed(object sender, EventArgs e)
        {
            if (pbPreviewProgress.InvokeRequired)
            {
                dVideoTimer_Elapsed d = new dVideoTimer_Elapsed(VideoTimer_Elapsed);
                this.Invoke(d, new object[] { sender, e });
            }
            else
            pbPreviewProgress.Value = (int)video.CurrentPosition;
        }

        private void ParseEL()
        {
            Working = true;
            ChangeButtonsEnabled();
            UpdateProcessState(eProcessState.Working);
            string elmainpage = DownloadWebPage(new Uri("http://elephantlist.com"));
            if (elmainpage.Length > 0)
            {
                string LinksHeader = "<!---- LINKS ---->";
                string LinksFooter = "<!---- ARCHIVE LINKS DESCRIPTION ---->";
                List<string> Lines = elmainpage.Split('\n').ToList<string>();

                ELSitesQueue.Clear();
                int StartIndex = Lines.IndexOf(LinksHeader) + 1;
                int EndIndex = Lines.IndexOf(LinksFooter) - 1;
                for (int i = StartIndex; i < EndIndex; i++)
                {
                    ELSitesQueue.Enqueue(Lines[i]);
                }
                OrigQueueSize = ELSitesQueue.Count;
                TotalPB.Value = 0;
                ResetThreadPB();
                if (OrigQueueSize > 0)
                    for (int i = 0; i < Settings.ThreadsCount; i++)
                    {
                        ThreadComplete[i] = false;
                        //Thread DLThread = new Thread(delegate() { SaveFile(i); });
                        Thread DLThread = new Thread(ParseSite);
                        DLThread.Start(i);
                    }
            }
        }

        private void ParseSite(object ThreadNum)
        {
            while ((ELSitesQueue.Count > 0) && (Working))
            {
                string SiteString;
                lock (ELSitesQueue)
                {
                    try
                    {
                        SiteString = ELSitesQueue.Dequeue();
                        int TotalPercentage = (int)(((double)(OrigQueueSize - ELSitesQueue.Count) / (double)OrigQueueSize) * 100);
                        UpdateTotalProgress(TotalPercentage);
                    }
                    catch
                    {
                        break;
                    }
                }

                UpdateTotalLabel(ELSitesQueue.Count);

                if (SiteString.Length < 6)
                    continue;
                SiteString = SiteString.Remove(0, 6);
                DateTime DTStamp;
                try
                {
                    DTStamp = new DateTime(DateTime.Now.Year, Convert.ToInt32(SiteString.Substring(0, 2)), Convert.ToInt32(SiteString.Substring(3, 2)));
                    if (DTStamp.Month > DateTime.Now.Month)
                        DTStamp = DTStamp.AddYears(-1);

                    int startahref = SiteString.IndexOf("<a href=", StringComparison.CurrentCultureIgnoreCase);
                    if (startahref == -1)
                        continue;
                    int endahref = SiteString.IndexOf("</a>", StringComparison.CurrentCultureIgnoreCase) + 4;
                    if (endahref == 3)
                        continue;
                    string ahref = SiteString.Substring(startahref, endahref - startahref).Trim();
                    stATag AhrefData = ExtractATag(ahref);
                    if ((AhrefData.Text.IndexOf("<") != -1) || (AhrefData.Text.IndexOf(">") != -1))
                        continue;
                    if (DBNull.Value.Equals(db.GetQueryObject("select LinkID from TLinks where Link = '" + AhrefData.Link + "'")))
                        if (Uri.IsWellFormedUriString(AhrefData.Link, UriKind.Absolute))
                        {
                            Guid SiteID = Guid.NewGuid();
                            List<string> SubLinks = GetSubLinks((int)ThreadNum, AhrefData.Link, SiteID);
                            if (SubLinks.Count > 0)
                            {
                                Guid Genre;
                                Guid SubGenre;
                                Guid SiteLink;
                                string sGenre = AhrefData.Text.Substring(AhrefData.Text.IndexOf(' ')).Trim();
                                string sSubGenre = AhrefData.Text.Substring(0, AhrefData.Text.IndexOf(' ')).Trim();
                                lock (db)
                                {
                                    Genre = db.GetOrInsertID("TGenres", new string[] { "GenreID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, sGenre }, new int[] { 1 });
                                    SubGenre = db.GetOrInsertID("TSubGenres", new string[] { "SubGenreID", "Name" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, sSubGenre }, new int[] { 1 });
                                    SiteLink = db.GetOrInsertID("Tlinks", new string[] { "LInkID", "Link" }, new FieldTypes[] { FieldTypes.u, FieldTypes.s }, new string[] { string.Empty, AhrefData.Link }, new int[] { 1 });
                                }

                                db.ExecuteQuery(@"insert into TSites ([SiteID]
                                    ,[RootSiteID]
		                            ,[GenreID]
		                            ,[SubGenreID]
		                            ,[LinkID]
		                            ,[DTStamp]) values
                                    ('" + SiteID + @"',
                                    '"+ELID.ToString()+@"',
                                    '" + Genre.ToString() + @"',
                                    '" + SubGenre.ToString() + @"',
                                    '" + SiteLink.ToString() + @"',
                                    '" + DTStamp.ToString("yyyy-MM-dd") + @"')");
                                db.ExecuteQueryBatch(SubLinks);
                            }
                        }
                }
                catch
                {
                }
            }
            ThreadComplete[(int)ThreadNum] = true;
            if (CheckForComplete())
            {
                Working = false;
                ChangeButtonsEnabled();
                UpdateStat();
                UpdateProcessState(eProcessState.Complete);
                UpdateTV(cbShowNewOnly.Checked);
                //MessageBox.Show("Готово");
            }
        }

        private void playToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((video != null) && (!video.Playing))
            {
                stopToolStripMenuItem.Enabled = true;
                playToolStripMenuItem.Enabled = false;
                VideoTimer.Start();
                video.Play();
            }
        }

        private void ResetThreadPB()
        {
            for (int i = 0; i < Settings.ThreadsCount; i++)
                SetThreadPBEnable(i, true);
        }

        private void SaveFile(object ThreadNum)
        {
            while ((SaveFileQueue.Count > 0) && (Working))
            {
                stSaveFileQueueItem SaveFileQueueItem;
                lock (SaveFileQueue)
                {
                    try
                    {
                        SaveFileQueueItem = SaveFileQueue.Dequeue();
                        int TotalPercentage = (int)(((double)(OrigQueueSize - SaveFileQueue.Count) / (double)OrigQueueSize) * 100);
                        UpdateTotalProgress(TotalPercentage);
                        UpdateTotalLabel(SaveFileQueue.Count);
                    }
                    catch
                    {
                        break;
                    }
                }

//                Guid RootSiteID = (Guid)db.GetQueryObject(@"Select TRS.RootSiteID from TSubLinks TSL left join 
//                                                        TSites TS on TSL.SiteID = TS.SiteID left join
//                                                        TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
//                                                        where TSL.SubLinkID = '" + SubLink.ToString() + "'");
                string Link;
                string FilePath;
                string LocalPath = string.Empty;
                if (SaveFileQueueItem.RootSiteID == ELID)
                {
                    db.ExecuteQuery("update TSublinks set DLTryings = DLTryings+1 Where SublinkID = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                    Link = db.GetQueryValue("Select TL.Link from TSubLinks TSL inner join TLinks TL on TSL.LinkID = TL.LinkID where TSL.SubLinkID = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                    try
                    {
                        LocalPath = db.GetQueryValue(@"Select (TRS.Name+'\'+TG.Name+'\'+TSG.Name+'\'+CONVERT(nvarchar(8),TS.DTStamp, 112)+'\'+CONVERT(nvarchar(36),TS.SiteID)+'\') Path from 
                            TSublinks TSL inner join 
                            TSites TS on TSL.SiteID = TS.SiteID inner join
                            TGenres TG on TS.GenreID = TG.GenreID inner join
                            TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID inner join
                            TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                            WHERE TSL.SublinkID = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                        FilePath = Path.Combine(Settings.RootPath, LocalPath);
                    }
                    catch (Exception)
                    {
                        WriteToLog("Error while combine path: '"+Settings.RootPath+"' and '"+LocalPath+"'");
                        break;
                    }
                    
                }
                else
                {
                    try
                    {
                        Link = db.GetQueryValue("Select TL.Link from TSites TS inner join TLinks TL on TS.LinkID = TL.LinkID where TS.SiteID = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                        LocalPath = db.GetQueryValue(@"Select (TRS.Name+'\'+TG.Name+'\'+TSG.Name+'\'+CONVERT(nvarchar(8),TS.DTStamp, 112)+'\'+CONVERT(nvarchar(36),TS.SiteID)+'\') Path from 
                    TSites TS inner join
                    TGenres TG on TS.GenreID = TG.GenreID inner join
                    TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID inner join
                    TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                    WHERE TS.SiteID = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                        FilePath = Path.Combine(Settings.RootPath, LocalPath);
                    }
                    catch (Exception)
                    {
                        
                        WriteToLog("Error while combine path: '"+Settings.RootPath+"' and '"+LocalPath+"'");
                        break;
                    }
                }
                
                
                if (!Directory.Exists(FilePath))
                    Directory.CreateDirectory(FilePath);
                //else
                //    foreach (string f in Directory.GetFiles(FilePath,"*.*"))
                //        File.Delete(f);
                string FullFileName = string.Empty;

                try
                {
                    FullFileName = Path.Combine(FilePath, Path.GetFileName(Link));
                }
                catch (Exception)
                {
                    
                    WriteToLog("Error while combine path: '"+FilePath+"' and '"+Link+"'");
                    break;
                }
                WriteToLog("Thread: "+ThreadNum.ToString()+" Trying to download file "+Link+" to "+FullFileName);
                WebClient wc = new WebClient();
                try
                {
                    
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Link);
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    response.Close();
                    Int64 FileSize = response.ContentLength;
                    using (Stream streamRemote = wc.OpenRead(Link))
                    {
                        using (Stream streamLocal = new FileStream(FullFileName, FileMode.Create, FileAccess.Write, FileShare.None))
                        {
                            int iByteSize = 0;
                            Int64 DownloadedBytes = 0;
                            byte[] byteBuffer = new byte[FileSize];
                            while ((iByteSize = streamRemote.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
                            {
                                streamLocal.Write(byteBuffer, 0, iByteSize);
                                DownloadedBytes += iByteSize;
                                int dProgressPercentage = (int)(((double)DownloadedBytes / (double)FileSize) * 100);
                                UpdateThreadStatus((int)ThreadNum, dProgressPercentage);
                            }
                            streamLocal.Close();
                            WriteToLog("Thread: " + ThreadNum.ToString() + " File downloaded: " + FullFileName + " Filesize: " + FileSize.ToString());
                            if (SaveFileQueueItem.RootSiteID == AGWID)
                            {
                                int SubImagesCount = CutImage(FullFileName);
                                GC.Collect();
                                
                                List<string> SubImagesQuery = new List<string>();
                                
                                for (int i = 0; i < SubImagesCount; i++)
                                {
                                    string LocalFileName = Path.GetFileNameWithoutExtension(FullFileName) + "_" + i.ToString() + Path.GetExtension(FullFileName);
                                    FileInfo fi = new FileInfo(Path.Combine(Path.GetDirectoryName(FullFileName),LocalFileName));
                                    long LocalFileSize = fi.Length;
                                    Guid LinkID = db.GetOrInsertID("TLinks",new string[]{"LinkID","Link"},new FieldTypes[] {FieldTypes.u, FieldTypes.s}, 
                                        new string[]{string.Empty, new Uri(new Uri(Link.Substring(0, Link.LastIndexOf('/') + 1)),LocalFileName).ToString()},new int[] {1});
                                    SubImagesQuery.Add(@"insert into tsublinks (Sublinkid, siteid, linkid, filesize, dltryings) 
                                                       values(NEWID(), '"+SaveFileQueueItem.ItemID.ToString()+@"',
                                                       '"+LinkID.ToString()+@"',"+LocalFileSize.ToString()+@", 0)");
                                }
                                db.ExecuteQueryBatch(SubImagesQuery);
                                try
                                {
                                    File.Delete(FullFileName);
                                }
                                catch (Exception)
                                {
                                    WriteToLog("Can't delete file: " + FullFileName);
                                }
                            }
                        }
                        streamRemote.Close();
                    }
                    //wc.DownloadFile(Link, FullFileName);
                    if (SaveFileQueueItem.RootSiteID == ELID)
                    {
                        FileInfo fi = new FileInfo(FullFileName);
                        db.ExecuteQuery("update TsubLInks set Filesize = " + fi.Length.ToString() + " where sublinkid = '" + SaveFileQueueItem.ItemID.ToString() + "'");
                    }
                }
                catch (Exception ex)
                {
                    WriteToLog("Thread: " + ThreadNum.ToString() + " Failed to download file: " + Link);
                    //MessageBox.Show(ex.Message);
                }
            }
            ThreadComplete[(int)ThreadNum] = true;
            if (CheckForComplete())
            {
                Working = false;
                ChangeButtonsEnabled();
                UpdateStat();
                UpdateProcessState(eProcessState.Complete);
                TV_AfterSelect(null, null);
                //UpdateTV(cbShowNewOnly.Checked);
                //MessageBox.Show("Готово");
            }
        }

        private void SaveFiles()
        {
            Working = true;
            ChangeButtonsEnabled();
            UpdateProcessState(eProcessState.Working);
            TotalPB.Value = 0;
            ResetThreadPB();
            for (int i = 0; i < Settings.ThreadsCount; i++)
            {
                ThreadComplete[i] = false;
                Thread DLThread = new Thread(SaveFile);
                DLThread.Start(i);
            }
        }

        private void SaveSettings()
        {
            XmlSerializer writer = new XmlSerializer(Settings.GetType());
            StreamWriter file = new StreamWriter(Application.StartupPath + @"\settings.xml", false, Encoding.UTF8);
            writer.Serialize(file, Settings);
            file.Close();
        }

        private void SetThreadPBEnable(int ThreadNum, bool Enabled)
        {
            if (statusStrip1.InvokeRequired)
            {
                dSetThreadPBEnable d = new dSetThreadPBEnable(SetThreadPBEnable);
                this.Invoke(d, new object[] { ThreadNum, Enabled });
            }
            else
            {
                ToolStripProgressBar tspbThread = (ToolStripProgressBar)statusStrip1.Items[1 + (ThreadNum * 2 + 1)];
                tspbThread.Enabled = Enabled;
            }

        }

        private void stopToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if ((video != null) && (video.Playing))
            {
                playToolStripMenuItem.Enabled = true;
                stopToolStripMenuItem.Enabled = false;
                VideoTimer.Stop();
                video.Stop();
            }
        }

        private void TV_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (TV.InvokeRequired)
            {
                dTV_AfterSelect d = new dTV_AfterSelect(TV_AfterSelect);
                this.Invoke(d, new object[] { sender, e});
            }
            else
            {
                if ((TV.SelectedNode != null) && (TV.SelectedNode.Level > 0))
                {
                    
                    string WhereString = " WHERE ";
                    switch (TV.SelectedNode.Level)
                    {
                        case 1:
                            {
                                WhereString += "TG.GenreID = '" + TV.SelectedNode.Name + "' ";
                                break;
                            }
                        case 2:
                            {
                                WhereString += "TSG.SubGenreID = '" + TV.SelectedNode.Name + "' AND TG.GenreID = '" + TV.SelectedNode.Parent.Name + "' ";
                                break;
                            }
                        case 3:
                            {
                                WhereString += "TS.DTStamp = '" + TV.SelectedNode.Name + "' AND TG.GenreID = '" + TV.SelectedNode.Parent.Parent.Name + "' AND TSG.SubGenreID = '" + TV.SelectedNode.Parent.Name + "' ";
                                break;
                            }
                        case 4:
                            {
                                WhereString += "TL2.Link = '" + TV.SelectedNode.Text + "' AND TS.DTStamp = '" + TV.SelectedNode.Parent.Name + "' AND TG.GenreID = '" + TV.SelectedNode.Parent.Parent.Parent.Name + "' AND TSG.SubGenreID = '" + TV.SelectedNode.Parent.Parent.Name + "' ";
                                break;
                            }
                    }
                    if (cbShowNewOnly.Checked)
                        WhereString += " AND TSL.FileSize = 0 ";
                    string Query = @"select TL.Link Link, TL.LinkID LinkID, TSL.FileSize FileSize, TSL.DLTryings Tryings from TSites TS
                    inner join TSubLinks TSL on TS.SiteID = TSL.SiteID
                    inner join TGenres TG on TS.GenreID = TG.GenreID
                    inner join TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID
                    inner join TLinks TL on TSL.LinkID = TL.LinkID
                    inner join TLinks TL2 on TS.LinkID = TL2.LinkID" +
                        WhereString +
                        @"order by TL.Link";
                    DataTable DT = db.GetQueryTable(Query);
                    if ((DTToTVThread != null) && (DTToTVThread.ThreadState == System.Threading.ThreadState.Running))
                        DTToTVThread.Abort();
                    DTToTVThread = new Thread(DTToLV);
                    DTToTVThread.Start(DT);
                }
            }
        }      

        private delegate void dDTToLV(object aDT);

        private void DTToLV(object aDT)
        {
            DataTable DT = (DataTable)aDT;
            ListViewItem[] lviArr = new ListViewItem[DT.Rows.Count];
            if (DT.Rows.Count > 0)
            {
                for (int i=0; i< DT.Rows.Count; i++)
                {
                    DataRow DR = DT.Rows[i];
                    ListViewItem lvi = new ListViewItem(DR["Link"].ToString());
                    lvi.Tag = DR["LinkID"];
                    lvi.SubItems.Add(DR["Filesize"].ToString());
                    lvi.SubItems.Add(DR["Tryings"].ToString());
                    lviArr[i] = lvi;
                }
            }
            if (lvLinks.InvokeRequired)
            {
                dDTToLV d = new dDTToLV(DTToLV);
                this.Invoke(d, new object[] { DT });
            }
            else
            {
                lvLinks.Items.Clear();                
                lvLinks.Items.AddRange(lviArr);
                lLinksCount.Text = lvLinks.Items.Count.ToString();
            }
                    
        }

        private void TV_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            TV.SelectedNode = e.Node;
        }

        private void UpdateProcessState(eProcessState ProcessState)
        {
            if (statusStrip1.InvokeRequired)
            {
                dUpdateProcessState d = new dUpdateProcessState(UpdateProcessState);
                this.Invoke(d, new object[] { ProcessState });
            }
            else
            {
                lProcessState.Text = ProcessState.ToString();
            }
        }

        private void UpdateStat()
        {
            if (lStat.InvokeRequired)
            {
                dUpdateStat d = new dUpdateStat(UpdateStat);
                this.Invoke(d);
            }
            else
            {
                int Sites = Convert.ToInt32(db.GetQueryValue("select count(SiteID) from TSites"));
                int Links = Convert.ToInt32(db.GetQueryValue("select count(SubLinkID) from TSubLinks"));
                int Downloaded = Convert.ToInt32(db.GetQueryValue("select count(SubLinkID) from TSubLinks where not Filesize = 0"));
                lStat.Text = string.Format("S:{0} L:{1} D:{2}", new object[] { Sites, Links, Downloaded });
            }
        }

        private void UpdateThreadStatus(int ThreadNum, int Percentage)
        {
            if (statusStrip1.InvokeRequired)
            {
                dUpdateThreadStatus d = new dUpdateThreadStatus(UpdateThreadStatus);
                this.Invoke(d, new object[] { ThreadNum, Percentage });
            }
            else
            {
                ToolStripProgressBar tspbThread = (ToolStripProgressBar)statusStrip1.Items[1 + (ThreadNum * 2 + 1)];
                tspbThread.Value = Percentage;
            }
        }

        private void UpdateTotalLabel(int Count)
        {
            if (statusStrip1.InvokeRequired)
            {
                dUpdateTotalLabel d = new dUpdateTotalLabel(UpdateTotalLabel);
                this.Invoke(d, new object[] { Count });
            }
            else
            {
                tsslTotalProgress.Text = (OrigQueueSize - Count).ToString() + "/" + OrigQueueSize.ToString();
            }
        }

        private void UpdateTotalProgress(int Percentage)
        {
            if (statusStrip1.InvokeRequired)
            {
                dUpdateTotalProgress d = new dUpdateTotalProgress(UpdateTotalProgress);
                this.Invoke(d, new object[] { Percentage });
            }
            else
            {
                TotalPB.ProgressBar.Value = Percentage;
            }
        }

        private void UpdateTV(bool ShowNewOnly)
        {
            if (TV.InvokeRequired)
            {
                dUpdateTV d = new dUpdateTV(UpdateTV);
                this.Invoke(d, new object[] { ShowNewOnly });
            }
            else
            {
                WriteToLog("Updating TV");
                TV.Nodes.Clear();
                lvLinks.Items.Clear();
                TreeNode ELNode = new TreeNode("ElephantList");
                ELNode.Name = ELID.ToString();
                ELNode.ImageIndex = 0;
                ELNode.SelectedImageIndex = 0;
                TreeNode AGWNode = new TreeNode("Amateurs Gone Wild");
                AGWNode.Name = AGWID.ToString();
                AGWNode.ImageIndex = 1;
                AGWNode.SelectedImageIndex = 1;
                TV.Nodes.Add(ELNode);
                TV.Nodes.Add(AGWNode);

               
                //load elephantlist
                WriteToLog("Load data for EL");
                string Query = @"select distinct TS.RootSiteID RootSiteID, TG.GenreID GID, TG.Name Genre, TSG.SubGenreID SGID, TSG.Name SubGenre, TS.DTStamp DateStamp, TS.SiteID SiteID, TL.Link Link from TSites TS
                inner join TGenres TG on TS.GenreID = TG.GenreID
                inner join TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID
                inner join TLinks TL on TS.LinkID = TL.LinkID
                inner join TSubLinks TSL on TS.SiteID = TSL.SiteID
                inner join TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                Where TSL.DLTryings < 10 AND TRS.RootSiteID = '" + ELID + "'";
                if (ShowNewOnly)
                    Query += " AND TSL.Filesize = 0";
                Query += " order by TG.Name, TSG.Name, TS.DTStamp, TL.Link";                
                DataTable DT = db.GetQueryTable(Query);
                DTToTV(DT, ELNode, AGWNode);

                //load AGW
                WriteToLog("Load data for AGW");
                Query = @"select distinct TS.RootSiteID RootSiteID, TG.GenreID GID, TG.Name Genre, TSG.SubGenreID SGID, TSG.Name SubGenre, TS.DTStamp DateStamp, TS.SiteID SiteID, TL.Link Link from TSites TS
                inner join TGenres TG on TS.GenreID = TG.GenreID
                inner join TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID
                inner join TLinks TL on TS.LinkID = TL.LinkID
                inner join TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                Where TRS.RootSiteID = '" + AGWID + "'";
                Query += " order by TG.Name, TSG.Name, TS.DTStamp, TL.Link";
                DT = db.GetQueryTable(Query);
                DTToTV(DT, ELNode, AGWNode);
            }
        }

        private void VideoEnding(object sender, EventArgs e)
        {
            playToolStripMenuItem.Enabled = true;
            stopToolStripMenuItem.Enabled = false;
            VideoTimer.Stop();
        }
        
        [Serializable]
        public class cSettings
        {

            public int AutoDownloadPeriod;
            public string RootPath;
            public string SDFFilename;
            public int ThreadsCount;



            public cSettings()
            {
                ThreadsCount = 10;
                AutoDownloadPeriod = 43200000;
                SDFFilename = string.Empty;
                RootPath = string.Empty;
            }
        }
        public struct stATag
        {

            public string Link;
            public string Text;
        }
        public struct stSaveFileQueueItem
        {
            public Guid RootSiteID;
            public Guid ItemID;
        }

        private void openFileToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (pbPreview.Tag != null)
            Process.Start(pbPreview.Tag.ToString());
        }

        private void openFolderToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (pbPreview.Tag != null)
            Process.Start("explorer.exe",Path.GetDirectoryName(pbPreview.Tag.ToString()));
        }

        private void splitContainer2_Panel2_Resize(object sender, EventArgs e)
        {
            if (video != null)
            {
                pbPreview.Height = splitContainer2.Panel2.ClientSize.Height-pbPreviewProgress.Height;
                pbPreview.Width = (int)(video.DefaultSize.Width * (double)(splitContainer2.Panel2.ClientSize.Height-pbPreviewProgress.Height) / (double)video.DefaultSize.Height);



                if (pbPreview.Width > splitContainer2.Panel2.ClientSize.Width)
                {
                    pbPreview.Height = (int)(pbPreview.Height * (double)splitContainer2.Panel2.ClientSize.Width / (double)pbPreview.Width);
                    pbPreview.Width = splitContainer2.Panel2.ClientSize.Width;
                }
            }
            pbPreview.Left = (splitContainer2.Panel2.ClientSize.Width - pbPreview.Width) / 2;
            pbPreview.Top = (splitContainer2.Panel2.ClientSize.Height - pbPreview.Height-pbPreviewProgress.Height) / 2;
        }


        private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            AutoDownloadRemainTimer.Stop();
            WriteToLog("Application stopped");
            Log.Close();
        }

        private void cleaToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure?", "Clear DB", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == System.Windows.Forms.DialogResult.Yes)
            {
                db.ExecuteQuery("delete from TGenres");
                db.ExecuteQuery("delete from TLinks");
                db.ExecuteQuery("delete from TSites");
                db.ExecuteQuery("delete from TSubGenres");
                db.ExecuteQuery("delete from TSubLinks");
                UpdateTV(cbShowNewOnly.Checked);
            }
        }

        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure?", "Delete files", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                return;
            stopToolStripMenuItem_Click(sender, e);
            if (video != null)
                video.Dispose();
            Guid RootSiteID = Guid.Empty;
            string GenreID = string.Empty;
            string SubGenreID = string.Empty;
            string DTStamp = string.Empty;
            string SiteID = string.Empty;
            if (TV.SelectedNode == null)
            {
                MessageBox.Show("Node are not selected");
                return;
            }
            //WriteToLog("Start download elements: " + TV.SelectedNode.FullPath);
            TreeNode TVNode = TV.SelectedNode;
            while (TVNode != null)
            {
                switch (TVNode.Level)
                {
                    case 0:
                        {
                            RootSiteID = new Guid(TVNode.Name);
                            break;
                        }
                    case 1:
                        {
                            GenreID = TVNode.Name;
                            break;
                        }
                    case 2:
                        {
                            SubGenreID = TVNode.Name;
                            break;
                        }
                    case 3:
                        {
                            DTStamp = TVNode.Name;
                            break;
                        }
                    case 4:
                        {
                            SiteID = TVNode.Name;
                            break;
                        }
                }
                TVNode = TVNode.Parent;
            }
            DataTable RecordsToDelete;
            List<string> FilesToDelete = new List<string>();
            List<string> DeleteQuery = new List<string>();
            string Where = " Where ";
            switch (TV.SelectedNode.Level)
            {
                case 0:
                    {
                        Where += " TS1.RootSiteID = '" + RootSiteID.ToString() + "'";
                        break;
                    }
                case 1:
                    {
                        Where += "TS1.GenreID = '" + GenreID + "'";
                        break;
                    }
                case 2:
                    {
                        Where += "TS1.SubGenreID = '" + SubGenreID + "'";
                        break;
                    }
                case 3:
                    {
                        Where += "TS1.DTStamp = '" + DTStamp + "'";
                        break;
                    }
                case 4:
                    {
                        Where += "TS1.SiteID = '" + SiteID + "'";
                        break;
                    }
            }

            DeleteQuery.Clear();
            //delete links for SubLink
            RecordsToDelete = db.GetQueryTable(@"select TSL1.LinkID, TL1.Link from TSubLinks TSL1 
                                            left join tsites TS1 on TSL1.SiteID=TS1.SiteID
                                            left join TLinks tl1 on TSl1.linkid=tl1.LinkID" + Where);
            if (RecordsToDelete.Rows.Count > 0)
                foreach (DataRow DR in RecordsToDelete.Rows)
                {
                    DeleteQuery.Add("delete from TLinks where LinkID = '" + DR[0].ToString() + "'");
                    string LocalPath = db.GetQueryValue(@"Select (TRS.Name+'\'+TG.Name+'\'+TSG.Name+'\'+CONVERT(nvarchar(8),TS.DTStamp, 112)+'\'+CONVERT(nvarchar(36),TS.SiteID)+'\') Path from 
                    TSublinks TSL inner join 
                    TSites TS on TSL.SiteID = TS.SiteID inner join
                    TGenres TG on TS.GenreID = TG.GenreID inner join
                    TSubGenres TSG on TS.SubGenreID = TSG.SubGenreID inner join
                    TLinks TL on TSL.LinkID = TL.LinkID inner join
                    TRootSites TRS on TS.RootSiteID = TRS.RootSiteID
                    WHERE TL.LinkID = '" + DR[0].ToString() + "'");
                    string FileName = Path.GetFileName(DR[1].ToString());
                    try
                    {
                        string FilePath = Path.Combine(Settings.RootPath, LocalPath);
                        string FullFileName = Path.Combine(FilePath, FileName);
                        FilesToDelete.Add(FullFileName);
                    }
                    catch (Exception)
                    {

                        WriteToLog("Error while combine '" + Settings.RootPath + "' and '" + LocalPath + "' and '" + FileName + "'");
                    }
                }
            //Delete Links for SiteLink
            RecordsToDelete = db.GetQueryTable("Select LinkID from TSites TS1"+Where);
            if (RecordsToDelete.Rows.Count > 0)
                foreach (DataRow DR in RecordsToDelete.Rows)
                    DeleteQuery.Add("delete from TLinks where LinkID = '" + DR[0].ToString() + "'");
            //delete sites
            RecordsToDelete = db.GetQueryTable("select TS1.SiteID from TSites TS1"+Where);
            if (RecordsToDelete.Rows.Count > 0)
                foreach (DataRow DR in RecordsToDelete.Rows)
                {
                    DeleteQuery.Add("delete from tsublinks where siteid='" + DR[0].ToString() + "'");
                    DeleteQuery.Add("delete from tsites where SiteID = '" + DR[0].ToString() + "'");
                }
            db.ExecuteQueryBatch(DeleteQuery);

            DeleteUnusedRecords();

            foreach (string Filename in FilesToDelete)
            {
                string FilePath = Path.GetDirectoryName(Filename);
                try
                {
                    File.Delete(Filename);

                    while ((Directory.GetFiles(FilePath).Length == 0) && (Directory.GetDirectories(FilePath).Length == 0))
                    {
                        Directory.Delete(FilePath);
                        FilePath = Path.GetDirectoryName(FilePath);
                    }

                }
                catch
                {
                    WriteToLog("Error while delete file: '" + Filename + "' or dir: '" + FilePath+"'");
                }
            }
            UpdateTV(cbShowNewOnly.Checked);
            UpdateGenresMenuItems();
            UpdateStat();
        }

        private void DeleteUnusedRecords()
        {
            List<string> DeleteQuery = new List<string>();
            DataTable RecordsToDelete;
            //delete unused genres, subgenres, rootsites
            DeleteQuery.Clear();
            //genres
            RecordsToDelete = db.GetQueryTable("SELECT distinct TG1.[GenreID] FROM [TGenres] TG1 left join TSites TS1 on TS1.GenreID = TG1.GenreID where TS1.GenreID is null");
            if (RecordsToDelete.Rows.Count > 0)
            {
                foreach (DataRow DR in RecordsToDelete.Rows)
                    DeleteQuery.Add("Delete from TGenres where GenreID = '" + DR[0].ToString() + "'");
            }
            //subgenres
            RecordsToDelete = db.GetQueryTable("SELECT distinct TSG1.[SubGenreID] FROM [TSubGenres] TSG1 left join TSites TS1 on TS1.SubGenreID = TSG1.SubGenreID where TS1.SubGenreID is null");
            if (RecordsToDelete.Rows.Count > 0)
            {
                foreach (DataRow DR in RecordsToDelete.Rows)
                    DeleteQuery.Add("Delete from TSubGenres where SubGenreID = '" + DR[0].ToString() + "'");
            }
            //RootSites
            RecordsToDelete = db.GetQueryTable("SELECT distinct TRS1.RootSiteID FROM [TRootSites] TRS1 left join TSites TS1 on TS1.RootSiteID = TRS1.RootSiteID where TS1.RootSiteID is null");
            if (RecordsToDelete.Rows.Count > 0)
            {
                foreach (DataRow DR in RecordsToDelete.Rows)
                    DeleteQuery.Add("Delete from TRootSites where RootSiteID = '" + DR[0].ToString() + "'");
            }
            db.ExecuteQueryBatch(DeleteQuery);
        }


        private ListViewColumnSorter lvwColumnSorter;

        private void lvLinks_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (e.Column == lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (lvwColumnSorter.Order == SortOrder.Ascending)
                {
                    lvwColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    lvwColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                lvwColumnSorter.SortColumn = e.Column;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            lvLinks.Sort();
        }

        public class ListViewColumnSorter : IComparer
        {
            /// <summary>
            /// Specifies the column to be sorted
            /// </summary>
            private int ColumnToSort;
            /// <summary>
            /// Specifies the order in which to sort (i.e. 'Ascending').
            /// </summary>
            private SortOrder OrderOfSort;
            /// <summary>
            /// Case insensitive comparer object
            /// </summary>
            private CaseInsensitiveComparer ObjectCompare;

            /// <summary>
            /// Class constructor.  Initializes various elements
            /// </summary>
            public ListViewColumnSorter()
            {
                // Initialize the column to '0'
                ColumnToSort = 0;

                // Initialize the sort order to 'none'
                OrderOfSort = SortOrder.None;

                // Initialize the CaseInsensitiveComparer object
                ObjectCompare = new CaseInsensitiveComparer();
            }

            /// <summary>
            /// This method is inherited from the IComparer interface.  It compares the two objects passed using a case insensitive comparison.
            /// </summary>
            /// <param name="x">First object to be compared</param>
            /// <param name="y">Second object to be compared</param>
            /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
            public int Compare(object x, object y)
            {
                int compareResult;
                ListViewItem listviewX, listviewY;

                // Cast the objects to be compared to ListViewItem objects
                listviewX = (ListViewItem)x;
                listviewY = (ListViewItem)y;

                // Compare the two items
                compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);

                // Calculate correct return value based on object comparison
                if (OrderOfSort == SortOrder.Ascending)
                {
                    // Ascending sort is selected, return normal result of compare operation
                    return compareResult;
                }
                else if (OrderOfSort == SortOrder.Descending)
                {
                    // Descending sort is selected, return negative result of compare operation
                    return (-compareResult);
                }
                else
                {
                    // Return '0' to indicate they are equal
                    return 0;
                }
            }

            /// <summary>
            /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
            /// </summary>
            public int SortColumn
            {
                set
                {
                    ColumnToSort = value;
                }
                get
                {
                    return ColumnToSort;
                }
            }

            /// <summary>
            /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
            /// </summary>
            public SortOrder Order
            {
                set
                {
                    OrderOfSort = value;
                }
                get
                {
                    return OrderOfSort;
                }
            }

        }

        private void DeleteBrokenLinks()
        {
            DataTable DT = db.GetQueryTable("Select * from TSubLinks where DLTryings = 10");
            List<string> DeleteQuery = new List<string>();
            if (DT.Rows.Count > 0)
            {
                foreach (DataRow DR in DT.Rows)
                {
                    DeleteQuery.Add("Delete from TLinks where LinkID = '" + DR["LinkID"].ToString() + "'");
                    DeleteQuery.Add("Delete from TSubLinks where SubLinkID = '" + DR["SublinkID"].ToString() + "'");
                }
            }
            db.ExecuteQueryBatch(DeleteQuery);
            DeleteQuery.Clear();
            DT = db.GetQueryTable("SELECT ts1.siteid, ts1.linkid from tsites ts1 left join tsublinks tsl1 on ts1.siteid = tsl1.siteid where tsl1.sublinkid is null");
            if (DT.Rows.Count > 0)
            {
                foreach (DataRow DR in DT.Rows)
                {
                    DeleteQuery.Add("delete from tsites where SiteID = '" + DR["SiteID"] + "'");
                    DeleteQuery.Add("Delete from TLinks where LinkID = '" + DR["LinkID"] + "'");
                }
            }
            db.ExecuteQueryBatch(DeleteQuery);
            DeleteUnusedRecords();
        }

        private void deleteBrokenLinksToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("Are you sure?", "Delete broken links", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
                return;
            DeleteBrokenLinks();
            UpdateTV(cbShowNewOnly.Checked);
            UpdateGenresMenuItems();
            UpdateStat();
        }

        private void checkBox1_CheckedChanged_1(object sender, EventArgs e)
        {
            TV_AfterSelect(null, null);
        }
    }
}